package libra.controller;

import java.time.LocalTime;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.nacos.api.naming.pojo.healthcheck.impl.Http;

@RestController
@RequestMapping("sentinel")
public class SentinelController {
	//******************** 测试“热点key”规则使用 ********************//
	/**
	 * Sentinel默认使用的资源命名方式是“/ControllerMapping/MethodMapping”
	 * @SentinelResource默认使用的资源命名方式是“当前方法的全类名路径”
	 * 可以在@SentinelResource注解的value属性中，以【Sentinel默认】的命名方式为资源命名，达到资源共用的目的，但是在dashboard中的数据会不准确！！！
	 */
	@RequestMapping("hotKeyWithParam")
	@SentinelResource(value="sentinel_hotKeyWithParam", blockHandler = "hotKeyWithParam_BlockHandler" )
	public Map<String, String> hotKeyWithParam( String k1, String k2 ){
		return BuildResp.createResp("success");
	}
	public Map<String, String> hotKeyWithParam_BlockHandler( String k1, String k2, BlockException ex ){
		return BuildResp.createResp("hotKeyWithParam_block");
	}
	
	@RequestMapping("hotKeyNoParam")
	@SentinelResource( blockHandler = "hotKeyNoParam_BlockHandler" )
	public Map<String, String> hotKeyNoParam(){
		return BuildResp.createResp("success");
	}
	public Map<String, String> hotKeyNoParam_BlockHandler( BlockException ex ){
		return BuildResp.createResp("hotKeyNoParam_block");
	}


	
	//******************** 测试“关联模式”限流规则使用 ********************//
	@Autowired
	SentinelService service;
	@RequestMapping("res1")
	public Map<String, String> res1(){
		return service.callRes("res1");
	}
	@RequestMapping("res2")
	public Map<String, String> res2(){
		return service.callRes("res2");
	}
	
	
	
	//******************** 测试@SentinelResource注解使用 ********************//
	//----- blockHandler & blockHandlerClass 配置使用 -----//
	/*
	 * 通过blockHandler属性指定流控处理函数
	 * 此方式配置需要满足：
	 * 		1、“处理函数”必须与“原函数”处于同一类中
	 * 		2、“处理函数”的参数列表、返回值与“原函数”一致
	 * 		3、“处理函数”的参数列表可在“原函数”的基础上添加一个类型为BlockException的异常参数
	 */
	@RequestMapping("annoByHandlerMethod")
	@SentinelResource( value="sentinel_annoByHandlerMethod", blockHandler="annoByHandlerMethod_BlockHandler" )
	public Map<String, String> annoByHandlerMethod( String param ){
		return BuildResp.createResp( String.format("success ... 【参数值：%s】", param) );
	}
	public Map<String, String> annoByHandlerMethod_BlockHandler(  String param, BlockException ex ){
		return BuildResp.createBlockResp( String.format("SentinelController.annoByHandlerMethod_BlockHandler() ... 【参数值：%s】", param) );
	}
	
	/*
	 * 通过blockHandlerClass属性指定流控处理函数，此方式“处理函数”可以在任意类中，不强制要求与“原函数”所属类一致。
	 * 此方式配置需要满足：
	 * 		1、“处理函数”必须为静态static函数，且blockHandler、blockHandlerClass属性需要同时都设置。
	 * 		2、blockHandlerClass属性为[]数组类型，可以配置多个。
	 * 		3、“处理函数”的参数列表、返回值与“原函数”一致
	 * 		4、“处理函数”的参数列表可在“原函数”的基础上添加一个类型为BlockException的异常参数
	 */
	@RequestMapping("annoByHandlerClass")
	@SentinelResource( value="sentinel_annoByHandlerClass", blockHandler="defaultBlockHandler", blockHandlerClass={SentinelHandler.class} )
	public Map<String, String> annoByHandlerClass( String param ){
		return BuildResp.createResp( String.format("success ... 【参数值：%s】", param) );
	}
	
	//----- fallback & fallbackClass & defaultFallback 配置使用 -----//
	/*
	 * 通过fallback属性指定异常处理函数，通过exceptionsToIgnore指定忽略处理的异常
	 * 此方式配置需满足：
	 * 		1、“处理函数”必须与“原函数”处于同一类中
	 * 		2、“处理函数”的参数列表、返回值与“原函数”一致
	 * 		3、“处理函数”的参数列表可在“原函数”的基础上添加一个类型为Throwable的异常参数
	 */
	@RequestMapping("annoByFallbackMethod")
	@SentinelResource( value="sentinel_annoByFallbackMethod", 
		blockHandler="defaultBlockHandler", blockHandlerClass={SentinelHandler.class},
		fallback = "annoByFallbackMethod_Fallback", exceptionsToIgnore={ ArithmeticException.class }
	)
	public Map<String, String> annoByFallbackMethod( String param ) throws Exception {
		if( "1".equals(param) ) {
			// 抛出java.lang.ArithmeticException
			int i = 1/0;
		} else if ( "2".equals(param) ) {
			throw new IllegalArgumentException( "手动抛出Java异常..." );
		} else if ( "3".equals(param) ) {
			throw new FlowException("手动抛出Block限流异常...");
		}
		return BuildResp.createResp( String.format("success ... 【参数值：%s】", param) );
	}
	public Map<String, String> annoByFallbackMethod_Fallback( String param, Throwable ex )  {
		return BuildResp.createFallbackResp( String.format("SentinelController.annoByFallbackMethod_Fallback() ... 【参数值：%s】 ... 【异常[ %s ]：%s】", 
				param, ex.getClass().getSimpleName(), ex.getMessage() ) );
	}
	
	/*
	 * 通过fallbackClass属性指定流控处理函数，此方式“处理函数”可以在任意类中，不强制要求与“原函数”所属类一致。通过exceptionsToIgnore指定忽略处理的异常
	 * 此方式配置需要满足：
	 * 		1、“处理函数”必须为静态static函数，且fallback、fallbackClass属性需要同时都设置。
	 * 		2、fallbackClass属性为[]数组类型，可以配置多个。
	 * 		3、“处理函数”的参数列表、返回值与“原函数”一致
	 * 		4、“处理函数”的参数列表可在“原函数”的基础上添加一个类型为Throwable的异常参数
	 */
	@RequestMapping("annoByFallbackClass")
	@SentinelResource( value="sentinel_annoByFallbackClass", 
		blockHandler="defaultBlockHandler", blockHandlerClass={SentinelHandler.class},
		fallback="dafaultFallback", fallbackClass={ SentinelFallback.class }, exceptionsToIgnore={ ArithmeticException.class } 
	)
	public Map<String, String> annoByFallbackClass( String param ) throws Exception{
		if( "1".equals(param) ) {
			// 抛出java.lang.ArithmeticException
			int i = 1/0;
		} else if ( "2".equals(param) ) {
			throw new IllegalArgumentException( "手动抛出Java异常..." );
		} else if ( "3".equals(param) ) {
			throw new FlowException("手动抛出Block限流异常...");
		}
		return BuildResp.createResp( String.format("success ... 【参数值：%s】", param) );
	}
	
	/*
	 * 通过defaultFallback属性指定异常处理函数
	 * 此方式配置需满足：
	 * 		1、“处理函数”必须与“原函数”处于同一类中
	 * 		2、“处理函数”的返回值与“原函数”一致
	 * 		3、“处理函数”的参数列表只能为空，或添加一个类型为Throwable的异常参数
	 */
	@RequestMapping("annoByDefaultFallbackMethod_1")
	@SentinelResource( value="sentinel_annoByDefaultFallbackMethod_1", defaultFallback="fallback_1")
	// 仅配置“defaultFallback”属性
	public Map<String, String> annoByDefaultFallbackMethod_1( String param ) throws Exception {
		// 抛出java.lang.ArithmeticException
		int i = 1/0;
		return BuildResp.createResp( String.format("success ... 【参数值：%s】", param) );
	}
	@RequestMapping("annoByDefaultFallbackMethod_2")
	@SentinelResource( value="sentinel_annoByDefaultFallbackMethod_2", defaultFallback="fallback_1", fallback ="fallback_2")
	// 配置“defaultFallback”、“fallback”属性
	public Map<String, String> annoByDefaultFallbackMethod_2( String param ) throws Exception {
		int i = 1/0;
		return BuildResp.createResp( String.format("success ... 【参数值：%s】", param) );
	}
	// 定义用于配置defaultFallback的异常处理函数，defaultFallback函数的参数列表只能为空，或者添加一个类型为Throwable 的参数，用于接收异常信息。
	public Map<String, String> fallback_1( Throwable ex )  {
		return BuildResp.createFallbackResp( String.format("SentinelController.fallback_1() ... 【异常[ %s ]：%s】", 
				ex.getClass().getSimpleName(), ex.getMessage() ) );
	}
	// 定义测试defaultFallback、fallback优先级的异常处理函数
	public Map<String, String> fallback_2(  String param, Throwable ex )  {
		return BuildResp.createFallbackResp( String.format("fallback_2() ... 【参数值：%s】 ... 【异常[ %s ]：%s】", 
				param, ex.getClass().getSimpleName(), ex.getMessage() ) );
	}


	
	//******************** 测试“熔断降级”规则使用 ********************//
	// 慢调用比例 的 “熔断”测试用例
	@RequestMapping("slowReqRatio")
	@SentinelResource(value="slow_req_ratio", blockHandler = "slowReqRatioBlockHandler")
	public Map<String, String> slowReqRatio( Boolean isSlow, HttpServletRequest req ) throws Exception{
		System.out.println( LocalTime.now() );
		if( isSlow ) 
			Thread.sleep(500);
		return BuildResp.createResp("success");
	}
	// 处理“熔断”逻辑
	public Map<String, String> slowReqRatioBlockHandler( Boolean isSlow, HttpServletRequest req, BlockException ex ) throws Exception{
		return BuildResp.createDegradeResp( "慢调用比例_BlockHandler【slowReqRatio】", ex );
	}
	
	// 异常比例 的 “熔断”测试用例
	@RequestMapping("errorRatio")
	@SentinelResource(value="error_ratio", blockHandler = "errorRatioBlockHandler", fallback = "errorRatioFallback")
	public Map<String, String> errorRatio( Boolean isError, HttpServletRequest req ) throws Exception{
		if( isError ) {
			int i = 1/0;
		}
		return BuildResp.createResp("success");
	}
	// 处理“熔断”逻辑
	public Map<String, String> errorRatioBlockHandler( Boolean isError, HttpServletRequest req, BlockException ex ) throws Exception{
		return BuildResp.createDegradeResp( "异常比例_BlockHandler【errorRatio】", ex );
	}
	// 处理程序执行异常
	public Map<String, String> errorRatioFallback( Boolean isError, HttpServletRequest req, Throwable throwable ) throws Exception{
		return BuildResp.createDegradeResp( "异常比例_Fallback【errorRatio】", throwable );
	}
	
	// 异常数 的 “熔断”测试用例
	@RequestMapping("errorCount")
	@SentinelResource(value="error_count", blockHandler = "errorCountBlockHandler", fallback = "errorCountFallback")
	public Map<String, String> errorCount( Boolean isError, HttpServletRequest req ) throws Exception{
		if( isError ) {
			int i = 1/0;
		}
		return BuildResp.createResp("success");
	}
	// 处理“熔断”逻辑
	public Map<String, String> errorCountBlockHandler( Boolean isError, HttpServletRequest req, BlockException ex ) throws Exception{
		return BuildResp.createDegradeResp( "异常数_BlockHandler【errorCount】", ex );
	}
	// 处理程序执行异常
	public Map<String, String> errorCountFallback( Boolean isError, HttpServletRequest req, Throwable throwable ) throws Exception{
		return BuildResp.createDegradeResp( "异常数_Fallback【errorCount】", throwable );
	}
}
